package com.xiaomaoguai.fcp.pre.kepler.trace.configuration;

import com.xiaomaoguai.fcp.pre.kepler.trace.constants.KeplerTraceConstant;
import com.xiaomaoguai.fcp.pre.kepler.trace.interceptor.CommonHandlerAroundInterceptor;
import com.xiaomaoguai.fcp.pre.kepler.trace.interceptor.HandlerInterceptorFactory;
import com.xiaomaoguai.fcp.pre.kepler.trace.interceptor.HeadHandlerAroundInterceptor;
import com.xiaomaoguai.fcp.pre.kepler.trace.interceptor.KeplerHandlerAspect;
import com.xiaomaoguai.fcp.pre.kepler.trace.interceptor.TailHandlerAroundInterceptor;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.api.HandlerContext;
import io.jaegertracing.internal.metrics.InMemoryMetricsFactory;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author August.Zhang
 * @version v1.0.0
 * @date 2020/1/6 10:02
 * @since JDK 1.8
 */
@Configuration
@ConditionalOnClass({
		HandlerContext.class,
		io.jaegertracing.internal.JaegerTracer.class,
		io.opentracing.contrib.java.spring.jaeger.starter.TracerBuilderCustomizer.class})
@ConditionalOnProperty(value = KeplerTraceConstant.KEPLER_OPENTRACING_JAEGER_ENABLED, havingValue = "true", matchIfMissing = true)
@AutoConfigureBefore(io.opentracing.contrib.java.spring.jaeger.starter.JaegerAutoConfiguration.class)
public class KeplerJaegerTraceAutoConfiguration {

	/**
	 * 绑定 traceId 、spanId 到 slf4j
	 * <ul>
	 * <li>将jaeger调用链的traceID等信息打印到logback里面，用于业务日志错误时，可以排查调用链信息，辅助排错
	 * </ul>
	 *
	 * @return TracerBuilderCustomizer 自定义 Tracer构建器
	 */
	@Bean(name = KeplerTraceConstant.TRACER_BUILDER_CUSTOMIZER_BEAN_NAME)
	@ConditionalOnMissingBean(name = KeplerTraceConstant.TRACER_BUILDER_CUSTOMIZER_BEAN_NAME)
	public io.opentracing.contrib.java.spring.jaeger.starter.TracerBuilderCustomizer zaTracerBuilderCustomizer() {
		return builder -> builder.withScopeManager(new WrappedThreadLocalScopeManager());
	}

	@Bean
	@ConditionalOnProperty(value = KeplerTraceConstant.KEPLER_OPENTRACING_JAEGER_METRICS_ENABLED, havingValue = "true", matchIfMissing = true)
	public InMemoryMetricsFactory metricsFactory() {
		return new InMemoryMetricsFactory();
	}

	@Bean
	public KeplerHandlerAspect openTracingKeplerHeadAspect() {
		return new KeplerHandlerAspect();
	}

	@Bean(name = KeplerTraceConstant.HANDLER_INTERCEPTOR_FACTORY_BEAN_NAME)
	@ConditionalOnMissingBean(name = KeplerTraceConstant.HANDLER_INTERCEPTOR_FACTORY_BEAN_NAME)
	public HandlerInterceptorFactory handlerInterceptorFactory() {
		return new HandlerInterceptorFactory();
	}

	@Bean(name = KeplerTraceConstant.HEAD_HANDLER_AROUND_INTERCEPTOR_BEAN_NAME)
	@ConditionalOnMissingBean(name = KeplerTraceConstant.HEAD_HANDLER_AROUND_INTERCEPTOR_BEAN_NAME)
	public HeadHandlerAroundInterceptor headHandlerAroundInterceptor() {
		return new HeadHandlerAroundInterceptor();
	}

	@Bean(name = KeplerTraceConstant.COMMON_HANDLER_AROUND_INTERCEPTOR_BEAN_NAME)
	@ConditionalOnMissingBean(name = KeplerTraceConstant.COMMON_HANDLER_AROUND_INTERCEPTOR_BEAN_NAME)
	public CommonHandlerAroundInterceptor commonHandlerAroundInterceptor() {
		return new CommonHandlerAroundInterceptor();
	}

	@Bean(name = KeplerTraceConstant.TAIL_HANDLER_AROUND_INTERCEPTOR_BEAN_NAME)
	@ConditionalOnMissingBean(name = KeplerTraceConstant.TAIL_HANDLER_AROUND_INTERCEPTOR_BEAN_NAME)
	public TailHandlerAroundInterceptor tailHandlerAroundInterceptor() {
		return new TailHandlerAroundInterceptor();
	}

}
